package com.xvdong.gadget;

/**
 * Created by xvDong on 2025/5/9.
 * 合并图片和PDF文件的工具,
 * 将图片和PDF合并成一个新的PDF文件
 */

import com.itextpdf.io.image.ImageData;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.utils.PdfMerger;

import java.awt.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.filechooser.FileSystemView;

public class FileMergerGUI extends JFrame {
    private JList<File> fileList;
    private DefaultListModel<File> listModel;
    private JButton addButton, removeButton, mergeButton;
    private JFileChooser fileChooser;
    private JProgressBar progressBar;

    public FileMergerGUI() {
        super("PDF/图片合并工具");
        initializeUI();
        setupEventListeners();
    }

    private void initializeUI() {
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(800, 600);
        setLocationRelativeTo(null);

        listModel = new DefaultListModel<>();
        fileList = new JList<>(listModel);
        fileList.setCellRenderer(new FileListRenderer());

        JPanel controlPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 10));
        addButton = new JButton("添加文件");
        removeButton = new JButton("移除选中");
        mergeButton = new JButton("开始合并");
        controlPanel.add(addButton);
        controlPanel.add(removeButton);
        controlPanel.add(mergeButton);

        progressBar = new JProgressBar(0, 100);
        progressBar.setStringPainted(true);

        fileChooser = new JFileChooser();
        fileChooser.setMultiSelectionEnabled(true);
        fileChooser.setFileFilter(new FileNameExtensionFilter(
                "支持的文件类型 (PDF, JPG, PNG)", "pdf", "jpg", "jpeg", "png"));

        setLayout(new BorderLayout(10, 10));
        add(new JScrollPane(fileList), BorderLayout.CENTER);
        add(controlPanel, BorderLayout.NORTH);
        add(progressBar, BorderLayout.SOUTH);
    }

    private void setupEventListeners() {
        addButton.addActionListener(e -> handleAddFiles());
        removeButton.addActionListener(e -> handleRemoveFiles());
        mergeButton.addActionListener(e -> handleMergeFiles());
    }

    private void handleAddFiles() {
        if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
            Arrays.stream(fileChooser.getSelectedFiles())
                    .filter(file -> !listModel.contains(file))
                    .forEach(listModel::addElement);
        }
    }

    private void handleRemoveFiles() {
        int[] indices = fileList.getSelectedIndices();
        for (int i = indices.length - 1; i >= 0; i--) {
            listModel.remove(indices[i]);
        }
    }

    private void handleMergeFiles() {
        JFileChooser saveChooser = new JFileChooser();
        saveChooser.setFileFilter(new FileNameExtensionFilter("PDF 文件", "pdf"));
        if (saveChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
            File outputFile = appendExtension(saveChooser.getSelectedFile());
            new MergeWorker(Collections.list(listModel.elements()), outputFile).execute();
        }
    }

    private File appendExtension(File file) {
        String path = file.getPath();
        return path.toLowerCase().endsWith(".pdf") ? file : new File(path + ".pdf");
    }

    class MergeWorker extends SwingWorker<Void, Integer> {
        private final List<File> files;
        private final File outputFile;

        MergeWorker(List<File> files, File outputFile) {
            this.files = new ArrayList<>(files);
            this.outputFile = outputFile;
        }

        @Override
        protected Void doInBackground() throws Exception {
            try (PdfWriter writer = new PdfWriter(new FileOutputStream(outputFile));
                 PdfDocument destDoc = new PdfDocument(writer)) {

                PdfMerger merger = new PdfMerger(destDoc);
                List<PdfDocument> openDocuments = new ArrayList<>();

                try {
                    int processed = 0;
                    for (File file : files) {
                        if (isPDF(file)) {
                            processPdfFile(file, merger, openDocuments);
                        } else {
                            processImageFile(file, destDoc);
                        }
                        processed++;
                        publish((processed * 100) / files.size());
                    }
                } finally {
                    closeAllDocuments(openDocuments);
                }
            }
            return null;
        }

        private void processPdfFile(File file, PdfMerger merger, List<PdfDocument> openDocuments)
                throws IOException {
            PdfDocument srcDoc = new PdfDocument(new PdfReader(file));
            openDocuments.add(srcDoc);
            merger.merge(srcDoc, 1, srcDoc.getNumberOfPages());
        }

        private void processImageFile(File imageFile, PdfDocument destDoc) throws IOException {
            ImageData imageData = ImageDataFactory.create(imageFile.getAbsolutePath());

            PageSize pageSize = PageSize.A4;
            PdfPage page = destDoc.addNewPage(pageSize);
            PdfCanvas canvas = new PdfCanvas(page);

            float imgWidth = imageData.getWidth();
            float imgHeight = imageData.getHeight();

            float margin = 36; // 0.5 inch
            float maxWidth = pageSize.getWidth() - 2 * margin;
            float maxHeight = pageSize.getHeight() - 2 * margin;

            float scale = Math.min(maxWidth / imgWidth, maxHeight / imgHeight);
            float scaledWidth = imgWidth * scale;
            float scaledHeight = imgHeight * scale;

            float x = (pageSize.getWidth() - scaledWidth) / 2;
            float y = (pageSize.getHeight() - scaledHeight) / 2;

            // 用矩阵添加图像（这是iText 7正确做法）
            canvas.addImageWithTransformationMatrix(
                    imageData,
                    scaledWidth, 0, 0, scaledHeight, // 缩放
                    x, y                              // 平移（位置）
            );
        }


        private void closeAllDocuments(List<PdfDocument> documents) {
            for (PdfDocument doc : documents) {
                if (!doc.isClosed()) {
                    doc.close();
                }
            }
        }

        @Override
        protected void process(List<Integer> chunks) {
            progressBar.setValue(chunks.get(chunks.size() - 1));
        }

        @Override
        protected void done() {
            try {
                get();
                JOptionPane.showMessageDialog(FileMergerGUI.this,
                        "合并成功！", "完成", JOptionPane.INFORMATION_MESSAGE);
            } catch (Exception e) {
                String errorMsg = e.getCause() != null ? e.getCause().getMessage() : e.getMessage();
                JOptionPane.showMessageDialog(FileMergerGUI.this,
                        "合并失败: " + errorMsg, "错误", JOptionPane.ERROR_MESSAGE);
            } finally {
                progressBar.setValue(0);
            }
        }

        private boolean isPDF(File file) {
            return file.getName().toLowerCase().endsWith(".pdf");
        }
    }

    class FileListRenderer extends DefaultListCellRenderer {
        @Override
        public Component getListCellRendererComponent(JList<?> list, Object value, int index,
                                                      boolean isSelected, boolean cellHasFocus) {
            super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
            File file = (File) value;
            setIcon(FileSystemView.getFileSystemView().getSystemIcon(file));
            setText(getDisplayText(file));
            return this;
        }

        private String getDisplayText(File file) {
            String type = file.getName().toLowerCase().endsWith(".pdf") ? "PDF" : "图片";
            return String.format("%s (%s)", file.getName(), type);
        }
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(() -> {
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                new FileMergerGUI().setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }
}
